﻿using SimpleHttpServer.Handler;
using System;
using System.Collections.Generic;
using System.Dynamic;
using System.Linq;
using System.Net.Http;
using System.Text.RegularExpressions;
using HandleHttp = SimpleHttpServer.HttpHandlerRegister.HandleHttp;

namespace SimpleHttpServer
{
	public class HttpHandlerWapper
	{
		/// <summary>
		/// 路径匹配表达式
		/// </summary>
		public string PathPattern { get; }

		/// <summary>
		/// 经过规范化处理路径正则匹配表达式
		/// </summary>
		public string MatchPathPattern { get; }

		/// <summary>
		/// 当含有路径变量时，改值为{路径变量名: 变量在路径中的位置}
		/// </summary>
		public Dictionary<string, int> PathParamsPos { get; }

		/// <summary>
		/// 请求方法
		/// </summary>
		public HttpMethod Method { get; }

		/// <summary>
		/// 请求处理Handler
		/// </summary>
		public HandleHttp HttpHandler { get; }

		public bool AllowCrossOrigin { get; }

		public HttpHandlerWapper(string pathPattern, string method, HandleHttp httpHandler, bool allowCrossOrigin)
		{
			if (string.IsNullOrWhiteSpace(pathPattern))
			{
				throw new ArgumentException($"不正确的匹配表达式: {pathPattern}");
			}

			if (httpHandler == null)
			{
				throw new ArgumentException("handler不可为null");
			}
			PathPattern = pathPattern;
			Method = new HttpMethod(method);
			HttpHandler = httpHandler;
			PathParamsPos = GetPathParamsPos();
			MatchPathPattern = StandardPathPattern();
			AllowCrossOrigin = allowCrossOrigin;
		}

		/// <summary>
		/// 获取路径请求参数信息： /a/:b/:c => {b: 2, c: 3}
		/// </summary>
		/// <returns></returns>
		private Dictionary<string, int> GetPathParamsPos()
		{
			Dictionary<string, int> pathDic = new Dictionary<string, int>();
			string[] pathArr = PathPattern.Split('/');
			for (var i = 0; i < pathArr.Length; i++)
			{
				if (pathArr[i].Length > 0 && pathArr[i][0] == ':')
				{
					string name = pathArr[i].Substring(1);
					if (!Regex.IsMatch(name, @"^[_a-zA-Z]\w*$"))
					{
						throw new ArgumentException($"{name}不是一个正确的路径变量名");
					}

					if (pathDic.ContainsKey(name))
					{
						throw new ArgumentException($"重复的路径变量:{name}");
					}
					pathDic.Add(name, i);
				}
			}
			return pathDic;
		}

		/// <summary>
		/// 获取规范化后的路径正则匹配表达式
		/// </summary>
		/// <returns>范化后的路径正则匹配表达式</returns>
		private string StandardPathPattern()
		{
			Dictionary<string, int> pathParamsPos = PathParamsPos ?? GetPathParamsPos();
			string[] pathArr = PathPattern.Split('/');
			foreach (var pair in pathParamsPos)
			{
				pathArr[pair.Value] = "*";
			}
			// 将表达式替换为正则
			for (var i = 0; i < pathArr.Length; i++)
			{
				if (pathParamsPos.Values.Contains(i))
				{
					pathArr[i] = @"(.*)?";
					continue;
				}
				string path = pathArr[i];
				pathArr[i] = path.Replace(".", @"\.").Replace("?", ".").Replace("*", "(.*)?");
			}
			return "^" + string.Join("/", pathArr) + "$";
		}

		public override string ToString()
		{
			return $"{nameof(PathPattern)}: {PathPattern}, {nameof(MatchPathPattern)}: {MatchPathPattern}, {nameof(PathParamsPos)}: {PathParamsPos}, {nameof(Method)}: {Method}";
		}
	}

	public class HttpHandlerRegister
	{
		/// <summary>
		/// 请求处理的标准委托
		/// </summary>
		/// <param name="ctx"></param>
		public delegate void HandleHttp(FxHttpContext ctx);

		private LinkedList<HttpHandlerWapper> handlerList;

		public HttpHandlerRegister()
		{
			handlerList = new LinkedList<HttpHandlerWapper>();
		}

		internal void RegisterHandler(HttpHandlerWapper handler)
		{
			handlerList.AddLast(handler);
		}

		internal void ClearHandler()
		{
			handlerList.Clear();
		}

		/// <summary>
		/// 开始处理请求
		/// </summary>
		/// <param name="ctx"></param>
		/// <returns></returns>
		public bool Handle(FxHttpContext ctx)
		{
			HttpHandlerWapper targetHandlerWapper = null;
			foreach (HttpHandlerWapper handlerWapper in handlerList)
			{
				if (Regex.IsMatch(ctx.Request.Path, handlerWapper.MatchPathPattern))
				{
					if (handlerWapper.Method.Method == ctx.Request.Method)
					{
						targetHandlerWapper = handlerWapper;
						if (handlerWapper.AllowCrossOrigin)
						{
							ctx.Response.AllowCrossOrigin();
						}
						break;
					}

					if (ctx.Request.Method == HttpMethod.Options.Method && handlerWapper.AllowCrossOrigin)
					{
						ctx.Response.AllowCrossOrigin();
						ctx.Response.SetBody("");
						ctx.Response.ReturnBody();
						return true;
					}
				}
			}

			if (targetHandlerWapper == null) return false;
			// 解析路径变量
			if (targetHandlerWapper.PathParamsPos.Count > 0)
			{
				string[] paths = ctx.Request.Path.Split('/');
				IDictionary<string, object> expandoObject = new ExpandoObject();
				foreach (KeyValuePair<string, int> pair in targetHandlerWapper.PathParamsPos)
				{
					if (pair.Value < paths.Length)
					{
						expandoObject[pair.Key] = paths[pair.Value];
					}
					else
					{
						throw new System.Exception($"不匹配的路径变量:{pair.Key}.");
					}
				}
				ctx.Request.PathParams = expandoObject;
			}
			// 处理请求
			targetHandlerWapper.HttpHandler.Invoke(ctx);
			// 返回响应结果
			ctx.Response.ReturnBody();
			return true;
		}
	}
}
